package com.liaoyin.travel.gate;

import io.jsonwebtoken.Claims;
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import lombok.Getter;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import com.liaoyin.travel.bean.UserInfo;

import java.io.Serializable;
import java.security.Key;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;

import javax.crypto.spec.SecretKeySpec;
import javax.xml.bind.DatatypeConverter;

/**
 *
 * token生成及解析类，通过jjwt生成及解析jwt的token
 *
 */
@Component
public class JwtTokenUtil implements Serializable {

    private static final long serialVersionUID = -3301605591108950415L;

    //用户名
    private static final String CLAIM_KEY_USERNAME = "sub";
    //创建时间
    private static final String CLAIM_KEY_CREATED = "created";

    //私钥
    //@Value("${spring.jwt.secret}")
    private static String secret="123456";

    //过期时间
    @Value("${spring.jwt.expiration}")
    @Getter
    private Long expiration;

    //获取用户名
    public String getUserNameFromToken(String token) {
        String userName;
        try {
            final Claims claims = getClaimsFromToken(token);
            userName = claims.getSubject();
        } catch (Exception e) {
        	userName = null;
        }
        return userName;
    }

    //获得创建时间
    public Date getCreatedDateFromToken(String token) {
        Date created;
        try {
            final Claims claims = getClaimsFromToken(token);
            created = new Date((Long) claims.get(CLAIM_KEY_CREATED));
        } catch (Exception e) {
            created = null;
        }
        return created;
    }

    //获取过期时间
    public Date getExpirationDateFromToken(String token) {
        Date expiration;
        try {
            final Claims claims = getClaimsFromToken(token);
            expiration = claims.getExpiration();
        } catch (Exception e) {
            expiration = null;
        }
        return expiration;
    }

    //解析token，需要传入秘钥
    private static Claims getClaimsFromToken(String token) {
        Claims claims;
        try {
            claims = Jwts.parser()
                    .setSigningKey(secret)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (Exception e) {
            claims = null;
        }
        return claims;
    }

    //生成过期时间
    private Date generateExpirationDate() {
        return new Date(System.currentTimeMillis() + expiration * 1000);
    }

    //验证token是否过期
    public Boolean isTokenExpired(String token) {
        final Date expiration = getExpirationDateFromToken(token);
        return expiration.before(new Date());
    }

    //判断token创建时间是否在最后一次修改密码之前
    private Boolean isCreatedBeforeLastPasswordReset(Date created, Date lastPasswordReset) {
        return (lastPasswordReset != null && created.before(lastPasswordReset));
    }

    //通过jjwt生成token，通过user生成
    public String generateToken(String userName) {
        Map<String, Object> claims = new HashMap<String, Object>();
        claims.put(CLAIM_KEY_USERNAME, userName);
        claims.put(CLAIM_KEY_CREATED, new Date());
        return generateToken(claims);
    }

    //通过jjwt生成token，通过传入map生成，claims中可以放入我们想放入的信息
    private String generateToken(Map<String, Object> claims) {
        return Jwts.builder()
                .setClaims(claims)
                .setExpiration(generateExpirationDate())
                .signWith(SignatureAlgorithm.HS512, secret)
                .compact();
    }

    //是否能刷新token，如密码修改后要重新登录才允许刷新token
    public Boolean canTokenBeRefreshed(String token, Date lastPasswordReset) {
        final Date created = getCreatedDateFromToken(token);
        return !isCreatedBeforeLastPasswordReset(created, lastPasswordReset)
                && !isTokenExpired(token);
    }

    //刷新token
    public String refreshToken(String token) {
        String refreshedToken;
        try {
            final Claims claims = getClaimsFromToken(token);
            claims.put(CLAIM_KEY_CREATED, new Date());
            refreshedToken = generateToken(claims);
        } catch (Exception e) {
            refreshedToken = null;
        }
        return refreshedToken;
    }

    //验证token是否有效
    public Boolean validateToken(String token, String userName) {
        final String tokenUserName = getUserNameFromToken(token);
        //final Date created = getCreatedDateFromToken(token);
        return tokenUserName.equals(userName) && !isTokenExpired(token);
    }
    
    /**
     * @method: createJWT
     * @Description: 前三个参数为自己用户token的一些信息比如id，权限，名称等。不要将隐私信息放入（大家都可以获取到） base64Security参数是秘钥
     * @param: [name, userId, role, audience, issuer, TTLMillis, base64Security]
     * @return: java.lang.String
     * @author: zhang.zhipeng
     * @Date: 2018/5/15 14:47
     **/
    public static String createJWT(String name, String userId,String nickName, String role,
                                   String audience, String issuer, long TTLMillis, String base64Security) {
        SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        //生成签名密钥 就是一个base64加密后的字符串？
        byte[] apiKeySecretBytes = DatatypeConverter.parseBase64Binary(base64Security);
        Key signingKey = new SecretKeySpec(apiKeySecretBytes, signatureAlgorithm.getJcaName());
        /*JSONObject jsonObject = new JSONObject();
        jsonObject.put("userName", name);
        jsonObject.put("userId", userId);
        jsonObject.put("nickName", nickName);*/
        //添加构成JWT的参数
        JwtBuilder builder = Jwts.builder().setHeaderParam("typ", "JWT")
                .setIssuedAt(now) //创建时间
                .setSubject(name+"#"+userId) //主题，也差不多是个人的一些信息
                .setIssuer(issuer) //发送谁
                .setAudience(audience) //个人签名
                .signWith(signatureAlgorithm, signingKey); //估计是第三段密钥,就是秘钥
        //添加Token过期时间
        if (TTLMillis >= 0) {
            //过期时间
            long expMillis = nowMillis + TTLMillis;
            //现在是什么时间
            Date exp = new Date(expMillis);
            //系统时间之前的token都是不可以被承认的
            builder.setExpiration(exp).setNotBefore(now);
        }
        //生成JWT
        return builder.compact();
    }
    
  //获取redis的keys
    public static String getRedisKeyFromToken(String token) {
        String user=null;
        UserInfo userInfo = null;
        try {
            final Claims claims = getClaimsFromToken(token);
            user = claims.getSubject();
            //userInfo = JsonUtil.getSingleBean(user,UserInfo.class);
            //loginType = (String) claims.get("userId");
        } catch (Exception e) {
            e.printStackTrace();
        }
        //System.out.println(userInfo.getAccount()+"#"+userInfo.getUserId());
        return user;
    }
}

